﻿/*=========================================================================

  Program:   ParaView
  Module:    FITKXMLCompositeDataWriter.h

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/**
 * @class   FITKXMLCompositeDataWriter
 * @brief   Writer for multi-group datasets
 *
 * FITKXMLCompositeDataWriter writes (serially) the VTK XML multi-group,
 * multi-block hierarchical and hierarchical box files. XML multi-group
 * data files are meta-files that point to a list of serial VTK XML files.
 * @sa
 * vtkXMLPCompositeDataWriter
 */

#ifndef FITKXMLCompositeDataWriter_h
#define FITKXMLCompositeDataWriter_h

#include <vtkIOXMLModule.h> // For export macro
#include <vtkStdString.h>   // needed for vtkStdString.
#include <vtkXMLWriter.h>
#include "FITKVTKAlgorithmAPI.h"

class vtkCallbackCommand;
class vtkCompositeDataSet;
class vtkXMLDataElement;
class FITKXMLCompositeDataWriterInternals;

class FITKVTKALGORITHMAPI FITKXMLCompositeDataWriter : public vtkXMLWriter
{
public:
    vtkTypeMacro(FITKXMLCompositeDataWriter, vtkXMLWriter);
    void PrintSelf(ostream& os, vtkIndent indent) override;

    /**
     * Get the default file extension for files written by this writer.
     */
    const char* GetDefaultFileExtension() override;

    /**
     * Get/Set the number of pieces into which the inputs are split.
     */

     ///@{
     /**
      * Get/Set the number of ghost levels to be written.
      */
    vtkGetMacro(GhostLevel, int);
    vtkSetMacro(GhostLevel, int);
    ///@}

    ///@{
    /**
     * Get/Set whether this instance will write the meta-file.
     */
    vtkGetMacro(WriteMetaFile, int);
    virtual void SetWriteMetaFile(int flag);
    ///@}

    /**
     * See the vtkAlgorithm for a description of what these do
     */
    vtkTypeBool ProcessRequest(
        vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;

protected:
    FITKXMLCompositeDataWriter();
    ~FITKXMLCompositeDataWriter() override;

    /**
     * Methods to define the file's major and minor version numbers.
     * Major version incremented since v0.1 composite data readers cannot read
     * the files written by this new reader.
     */
    int GetDataSetMajorVersion() override { return 1; }
    int GetDataSetMinorVersion() override { return 0; }

    /**
     * Create a filename for the given index.
     */
    vtkStdString CreatePieceFileName(int Piece);
    /**
     * @brief    通过数据块索引获取文件类型
     * @param[i] piece                数据块索引
     * @return   int                  类型
     * @author   BaGuijun (baguijun@163.com)
     * @date     2025-05-21
     */
    int GetFileTypeByPiece(int piece);

    // see algorithm for more info
    int FillInputPortInformation(int port, vtkInformation* info) override;

    int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
    int RequestUpdateExtent(vtkInformation*, vtkInformationVector**, vtkInformationVector*);

    int WriteData() override;
    const char* GetDataSetName() override;

    // Create a default executive.
    vtkExecutive* CreateDefaultExecutive() override;

    vtkInformation* InputInformation;

    /**
     * Determine the data types for each of the leaf nodes.
     */
    virtual void FillDataTypes(vtkCompositeDataSet*);

    /**
     * Returns the number of leaf nodes (also includes empty leaf nodes).
     */
    unsigned int GetNumberOfDataTypes();

    /**
     * Returns the array pointer to the array of leaf nodes.
     */
    int* GetDataTypesPointer();

    // Methods to create the set of writers matching the set of inputs.
    void CreateWriters(vtkCompositeDataSet*);
    vtkXMLWriter* GetWriter(int index);

    // Methods to help construct internal file names.
    void SplitFileName();
    const char* GetFilePrefix();
    const char* GetFilePath();

    /**
     * Returns the default extension to use for the given dataset type.
     * Returns nullptr if an extension cannot be determined.
     */
    const char* GetDefaultFileExtensionForDataSet(int dataset_type);

    /**
     * Write the collection file if it is requested.
     * This is overridden in parallel writers to communicate the hierarchy to the
     * root which then write the meta file.
     */
    int WriteMetaFileIfRequested();

    // Make a directory.
    void MakeDirectory(const char* name);

    // Remove a directory.
    void RemoveADirectory(const char* name);

    // Internal implementation details.
    FITKXMLCompositeDataWriterInternals* Internal;

    // The number of ghost levels to write for unstructured data.
    int GhostLevel;

    /**
     * Whether to write the collection file on this node. This could
     * potentially be set to 0 (i.e. do not write) for optimization
     * if the file structured does not change but the data does.
     */
    int WriteMetaFile;

    // Callback registered with the InternalProgressObserver.
    static void ProgressCallbackFunction(vtkObject*, unsigned long, void*, void*);
    // Progress callback from internal writer.
    virtual void ProgressCallback(vtkAlgorithm* w);

    // The observer to report progress from the internal writer.
    vtkCallbackCommand* InternalProgressObserver;

    /**
     * Internal method called recursively to create the xml tree for
     * the children of compositeData as well as write the actual data
     * set files.  element will only have added nested information.
     * writerIdx is the global piece index used to create unique
     * filenames for each file written.
     * This function returns 0 if no files were written from
     * compositeData.
     */
    virtual int WriteComposite(
        vtkCompositeDataSet* compositeData, vtkXMLDataElement* element, int& writerIdx) = 0;

    /**
     * Internal method to write a non vtkCompositeDataSet subclass as
     * well as add in the file name to the metadata file.
     * Element is the containing XML metadata element that may
     * have data overwritten and added to (the index XML attribute
     * should not be touched though).  writerIdx is the piece index
     * that gets incremented for the globally numbered piece.
     * This function returns 0 if no file was written (not necessarily an error).
     * this->ErrorCode is set on error.
     */
    virtual int WriteNonCompositeData(
        vtkDataObject* dObj, vtkXMLDataElement* element, int& writerIdx, const char* fileName);

    /**
     * Utility function to remove any already written files
     * in case writer failed.
     */
    virtual void RemoveWrittenFiles(const char* SubDirectory);

private:
    FITKXMLCompositeDataWriter(const FITKXMLCompositeDataWriter&) = delete;
    void operator=(const FITKXMLCompositeDataWriter&) = delete;
};

#endif
